import { isPromise, isObject } from "./share";
import Xhr from "./xhr";

// ajax.ts
interface Config {
    url: string;
    data?: object;
    type?: string;
    dataType?: string;
    async?: boolean;
    //config包含header设置 和 其他与请求无关的辅助数据
    config?: any;
}

abstract class TsAjax {
    abstract post(obj: Config): any;
    abstract get(obj: Config): any;
    abstract proxyPost(obj: Config): any;
    abstract proxyGet(obj: Config): any;
}

// hooks
abstract class Hooks extends Xhr {
    //默认全局配置项
    readonly config: any;

    //代理map
    private proxyMap: any = new Map();

    constructor() {
        super();
        this.config = this.getDefaultConfig();
    }

    private getDefaultConfig(): object {
        return {
            baseURL: "",
            type: "GET",
            async: true,
            dataType: "json",
            config: {},
            timeout: 10000,
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            }
        };
    }

    //代理相关的
    protected isProxy(object: Config): boolean {
        let key = object.url;
        return this.proxyMap.has(key);
    }

    protected addProxy(object: Config): any {
        let key = object.url;
        this.proxyMap.set(key, 1);
        return this;
    }

    protected delProxy(object: Config): any {
        let key = object.url,
            proxyTime = isObject(object.config) ? object.config.proxyTime : 0;
        if (!proxyTime) {
            this.proxyMap.delete(key);
        } else {
            setTimeout(() => {
                this.delProxy({ url: key });
                console.warn("已在队列中清除代理信息, 代理目标：" + key);
            }, object.config.proxyTime);
        }
        return this;
    }

    //请求拦截器
    protected InjectRequest(object: Config): any {
        //这里可以做一些全局性的请求设置
        // Promise.reject()拦截
        //.....

        //返回这个对象继续请求
        return object;
    }
    //响应拦截器
    protected InterctResponse(config: any, promise: any, response: any) {
        // 这里可以做一些全局性的拦截设置
        // Promise.reject()拦截
        // .....

        //返回promise继续响应
        return promise;
    }

    //请求参数合并
    protected assignConfig(Config: Config) {
        return {
            ...this.config,
            ...Config,
            config: {
                //是否使用worker请求
                webworker: false,
                //单次代理时间, 仅在上面 webworker = false下有效
                proxyTime: 0,
                ...Config.config
            },
            headers: {
                ...this.config.headers,
                ...(Config.config ? Config.config.headers : {})
            }
        };
    }

    //发起异步请求函数、请求返回处理函数
    private async asyncMiddleAction(config: any) {
        let response: any = null;
        let result = await this.xmlRequestAsync(config).then((res: any) => {
            response = res;
            return res;
        });
        this.delProxy(config);
        return this.InterctResponse(config, Promise.resolve(result), response);
    }

    ajax(Config: Config) {
        let config = this.assignConfig(Config);
        let Inject = this.InjectRequest(config);
        //console.log(config);

        //请求前拦截处理
        if (isPromise(Inject)) return Inject;

        //同步 /异步
        return config.async === false
            ? this.xmlRequest(config)
            : this.asyncMiddleAction(config);
    }
}

export class Ajax extends Hooks implements TsAjax {
    constructor() {
        super();
    }

    post(object: Config): any {
        return this.ajax({ ...object, type: "POST" });
    }

    get(object: Config): any {
        return this.ajax({ ...object, type: "GET" });
    }

    proxyPost(object: Config): any {
        if (this.isProxy(object))
            return Promise.reject(
                "对不起，本次请求正在处理中，请等待本次结束..."
            );
        return this.addProxy(object).post(object);
    }

    proxyGet(object: Config): any {
        if (this.isProxy(object))
            return Promise.reject(
                "对不起，本次请求正在处理中，请等待本次结束..."
            );
        return this.addProxy(object).get(object);
    }
}
